﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpParameterLevelList.h"
#include "ILevel.h"
#include "LevelUtils.h"
#include "IParameterValueStorage.h"
#include "UniIdentity.h"
#include "IDocument.h"
#include "IElement.h"
#include "IWorkPlane.h"
#include "IParameterValueElementId.h"
#include "IElementBasicInformation.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IElementPositionReportComponent.h"
#include "GbmpDocUtils.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

DATA_DEFINE(GbmpParameterLevelList)
{
}

GbmpParameterLevelList::GbmpParameterLevelList(const UniIdentity& uid)
    : GbmpParameterValueListBase(uid)
{
}

OwnerPtr<IParameterValueList> GbmpParameterLevelList::Clone() const
{
    return NEW_AS_OWNER_PTR(GbmpParameterLevelList, *this);
}

std::wstring GbmpParameterLevelList::OnGetDisplayStringByValue(const IDocument* pDoc, const IParameterValueStorage* pValue) const
{
    std::wstring res;
    DBG_WARN_AND_RETURN_UNLESS(pDoc, res, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(pValue, res, L"pValue为空",L"GDMPLab",L"2024-03-30");

    const IParameterValueElementId* pElementId = dynamic_cast<const IParameterValueElementId*>(pValue);
    DBG_WARN_AND_RETURN_UNLESS(pElementId, res, L"pElementId为空",L"GDMPLab",L"2024-03-30");

    if (!pElementId->GetValue().IsValid())
    {
        return GbmpParameterValueListBase::s_nullName;
    }

    ILevel* pLevel = LevelUtils::GetLevelById(pDoc, pElementId->GetValue());
    if (pLevel)
    {
        return pLevel->GetName();
    }

    //////////////////////////////////////////////////////////////////////////
    // TODO: 为支持族文档标高参数仍能使用旧版标高。
    {
        const IElement* pLegacyLevel = pDoc->GetElement(pElementId->GetValue());
        if (pLegacyLevel)
        {
            const IWorkPlane* pWorkPlane = dynamic_cast<const IWorkPlane*>(pLegacyLevel);
            if (pWorkPlane && pWorkPlane->GetReferencedPlaneId().IsValid())
            {
                const IElement* pRefPlane = pDoc->GetElement(pWorkPlane->GetReferencedPlaneId());
                return pRefPlane->GetBasicInformation()->GetName();
            }
             
            return pLegacyLevel->GetBasicInformation()->GetName();
        }            
    }
    //////////////////////////////////////////////////////////////////////////

    return res;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: 此类为支持族文档标高参数仍能使用旧版标高临时创建。待老标高清除使用后可删掉
class GBMP_MODEL_EXPORT LowerLevelComparer
{
public:
    bool operator() (const IElement *pLeft, const IElement *pRight) const 
    {
        double leftHeight = 0.0, rightHeight = 0.0;
        const IElementPositionReportComponent *pLeftBehavior = pLeft->GetElementPositionReportComponent();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLeftBehavior, L"pLeftBehavior无效",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLeftBehavior->GetHeight(leftHeight), L"获取高度失败",L"GDMPLab",L"2024-03-30");
        const IElementPositionReportComponent * pRightBehavior = pRight->GetElementPositionReportComponent();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pRightBehavior, L"pRightBehavior无效",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pRightBehavior->GetHeight(rightHeight), L"获取高度失败",L"GDMPLab",L"2024-03-30");

        if (MathUtils::IsLessThan(leftHeight, rightHeight, Constants::LENGTH_EPS))
            return true;

        if (MathUtils::IsGreaterThan(leftHeight, rightHeight, Constants::LENGTH_EPS))
            return false;

        return pLeft->GetElementId() > pRight->GetElementId();
    };
};
//////////////////////////////////////////////////////////////////////////

std::vector<OwnerPtr<IParameterValueStorage>> GbmpParameterLevelList::OnGetValues(const IDocument* pDoc, const std::vector<ElementId>& ids/* = std::vector<ElementId>()*/) const
{
    std::vector<OwnerPtr<IParameterValueStorage>> res;
    DBG_WARN_AND_RETURN_UNLESS(pDoc, res, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    std::vector<const ILevel *> levels = LevelUtils::GetLevelsFromHighToLow(pDoc);
    FOR_EACH (pLevel, levels)
    {
        res.emplace_back(IParameterValueElementId::Create(pLevel->GetOwnerElement()->GetElementId()));
    }

    //////////////////////////////////////////////////////////////////////////
    // TODO: 为支持族文档标高参数仍能使用旧版标高。
    {
        //判断一下是否已经被上面获得了新标高，否则就是老标高
        if (!(levels.size() > 0))
        {
            std::vector<IElement*> oldLevelElements = gcmp::GbmpDocUtils::GetElementsByCategory(pDoc, BuiltInCategoryUniIdentities::BICU_ELEVATION);
            std::sort(oldLevelElements.begin(), oldLevelElements.end(), LowerLevelComparer());
            FOR_EACH(pOldLevel, oldLevelElements)
            {
                res.emplace_back(IParameterValueElementId::Create(pOldLevel->GetElementId()));
            }
        }
    }
    //////////////////////////////////////////////////////////////////////////
    return res;
}
